package com.huice.base;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import org.openqa.selenium.*;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.Select;
import org.openqa.selenium.support.ui.WebDriverWait;

import javax.annotation.Nonnull;

public class Locator {

    private XmlParser xp;
    private WebDriver mDriver;
    public final int TIMEOUT;
    private Set<String> mWindowHandles = new TreeSet<>();

    public Locator(WebDriver driver, String path, int timeout) {
        this.TIMEOUT = timeout;
        this.mDriver = driver;
        xp = new XmlParser(path);
    }

    public void wait(int time) {
        int millis = time * 1000;
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public boolean linkTo(String url) {
        try {
            mDriver.get(url);
            return true;
        } catch (Exception e) {
            Log.info("链接:" + url + "加载超时");
            return false;
        }
    }

    public void click(String page, String object) {
        getElement(page, object).click();
    }

    public void sendKeys(String page, String object, String text) {
        WebElement element = getElement(page, object);
        element.click();
        element.clear();
        element.sendKeys(text);
    }

    /**
     * @return 返回当前操作的设备
     */
    public WebDriver getDriver() {
        return mDriver;
    }

    public String getText(String page, String object) {
        return getElement(page, object).getText();
    }

    public String getAttribute(String page, String object, String attribute) {
        return getElement(page, object).getAttribute(attribute);
    }

    public Select select(String page, String object) {
        return new Select(getElement(page, object));
    }


    public void doRandomSelect(String page, String object, int start) {
        Select select1 = new Select(getElement(page, object));
        double random = Math.random() * (select1.getOptions().size() - start) + start;
        int k = (int) random;
        select1.selectByIndex(k);
    }

    public void doSelect(String page, String object, String type, String value) {
        Select select = new Select(getElement(page, object));
        switch (type.toLowerCase()) {
            case "index":
                select.selectByIndex(Integer.parseInt(value.toString()));
                break;
            case "value":
                select.selectByValue(value.toString());
                break;
            case "text":
                select.selectByVisibleText(value.toString());
                break;
            default:
                Log.info("类型不存在");
                break;
        }
    }

    public int getElementsCount(String page, String object) {

        return getElements(page, object).size();

    }


    public boolean swtichWindowByTitle(String title) {

        Set<String> handles = mDriver.getWindowHandles();

        for (String handle : handles) {
            mDriver.switchTo().window(handle);
            if (mDriver.getTitle().contains(title)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 切换到最新打开的页面
     */
    public void swtichNextWindow() {
        Set<String> handles = mDriver.getWindowHandles();
        if (handles.size() > 0) {
            Object[] arrayHandle = handles.toArray();
            String nextHandle = String.valueOf(arrayHandle[arrayHandle.length - 1]);
            mDriver.switchTo().window(nextHandle);
        }
    }

    public void scrollToBottom() {
        String jsString = "scrollTo(0,10000);";
        addJS(jsString);
    }

    public void addJS(String jsCodes) {
        JavascriptExecutor jsExecutor = (JavascriptExecutor) mDriver;
        jsExecutor.executeScript(jsCodes);
    }

    /**
     * 去除只读属性
     */
    public void removeReadonly(String id) {
        String jsString = "document.getElementById(\"" + id + "\").removeAttribute(\"readonly\");";
        addJS(jsString);

    }

    /**
     * 记录当前窗体,与{@link #waitHasNewWindows()}配合使用
     */
    public void recordWindows() {
        mWindowHandles = mDriver.getWindowHandles();
    }

    /**
     * 等待浏览器内打开的网页标签数变化后返回
     *
     * @return false:在规定时间内未能满足要求
     */
    public boolean waitHasNewWindows() {
        final int size = mWindowHandles.size();
        Boolean flag;
        try {
            flag = new WebDriverWait(mDriver, TIMEOUT).until(new ExpectedCondition<Boolean>() {
                @Override
                public Boolean apply(@Nonnull WebDriver d) {
                    return mDriver.getWindowHandles().size() != size;
                }
            });
        } catch (Exception e) {
            return false;
        }
        return flag;
    }

    /**
     * 等待弹出Alert
     *
     * @return false:在规定时间内未能满足要求
     * * @see #switchToAlert()
     */
    public boolean waitAlert() {
        boolean flag;
        try {
            flag = new WebDriverWait(mDriver, TIMEOUT).until(ExpectedConditions.alertIsPresent()) != null;
        } catch (Exception e) {
            return false;
        }
        return flag;
    }


    /**
     * 尝试切换到Alert，如果成功返回true,没有Alert返回false,可以用于验证是否存在Alert.
     *
     * @see #waitAlert()
     */
    public Alert switchToAlert() {
        try {
            return mDriver.switchTo().alert();
        } catch (NoAlertPresentException e) {
            return null;
        }
    }


    /**
     * 等待网页的url与入参url相同，可以用于监控网页的跳转
     *
     * @return false:在规定时间内未能满足要求
     * @see #waitNotUrl(String)
     */
    public boolean waitToUrl(String url) {
        Boolean flag;
        try {
            flag = new WebDriverWait(mDriver, TIMEOUT).until(new ExpectedCondition<Boolean>() {
                @Override

                public Boolean apply(@Nonnull WebDriver driver) {
                    return driver.getCurrentUrl().equals(url);
                }
            });
        } catch (Exception e) {
            return false;
        }
        return flag;
    }

    /**
     * 等待网页的url以入参url为前缀，可以用于监控网页的跳转
     *
     * @return false:在规定时间内未能满足要求
     * @see #waitToUrl(String)
     */
    public boolean waitToUrlStartsWith(String url) {
        Boolean flag;
        try {
            flag = new WebDriverWait(mDriver, TIMEOUT).until(new ExpectedCondition<Boolean>() {
                @Override

                public Boolean apply(@Nonnull WebDriver driver) {
                    return driver.getCurrentUrl().startsWith(url);
                }
            });
        } catch (Exception e) {
            return false;
        }
        return flag;
    }

    /**
     * 等待网页的url与入参url不同，可以用于监控网页的跳转
     *
     * @return false:在规定时间内未能满足要求
     * @see #waitToUrl(String)
     */
    public boolean waitNotUrl(String url) {
        Boolean flag;
        try {
            flag = new WebDriverWait(mDriver, TIMEOUT).until(new ExpectedCondition<Boolean>() {
                @Override

                public Boolean apply(@Nonnull WebDriver driver) {
                    return !driver.getCurrentUrl().equals(url);
                }
            });
        } catch (Exception e) {
            return false;
        }
        return flag;
    }

    /**
     * 等待网页的url不再入参url为前缀，可以用于监控网页的跳转
     *
     * @return false:在规定时间内未能满足要求
     * @see #waitNotUrl(String)
     */
    public boolean waitNotUrlStartsWith(String url) {
        Boolean flag;
        try {
            flag = new WebDriverWait(mDriver, TIMEOUT).until(new ExpectedCondition<Boolean>() {
                @Override

                public Boolean apply(@Nonnull WebDriver driver) {
                    return !driver.getCurrentUrl().startsWith(url);
                }
            });
        } catch (Exception e) {
            return false;
        }
        return flag;
    }

    public boolean elementIsPresent(String page, String object) {
        final By by = getBy(page, object);
        Boolean flag = false;
        try {
            flag = new WebDriverWait(mDriver, TIMEOUT).until(new ExpectedCondition<Boolean>() {
                @Override
                public Boolean apply(WebDriver d) {
                    d.findElement(by);
                    return true;
                }
            });
        } catch (Exception e) {

        }
        return flag;
    }

    public void addCookies(String url, Map<String, String> cookies) {
        mDriver.get(url);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for (String key : cookies.keySet()) {
            mDriver.manage().addCookie(new Cookie(key, cookies.get(key)));
        }

        mDriver.get(url);
    }
//----------------------------------------------------------------------------------	

    private boolean elementIsDisplay(final WebElement element) {
        Boolean flag = false;

        flag = new WebDriverWait(mDriver, TIMEOUT).until(new ExpectedCondition<Boolean>() {

            @Override
            public Boolean apply(WebDriver d) {
                return element.isDisplayed();
            }
        });
        return flag;
    }

    public WebElement getElement(String page, String object) {
        By by = getBy(page, object);
        WebElement element = waitElement(by);
        if (elementIsDisplay(element)) {
            return element;
        } else {
            Log.info("对象不存在");
            return null;
        }
    }

    public List<WebElement> getElements(String page, String object) {
        By by = getBy(page, object);
        List<WebElement> elements = mDriver.findElements(by);
        if (elements == null) {
            Log.info("对象不存在");
            return null;
        } else {
            return elements;
        }
    }

    private WebElement waitElement(final By by) {
        WebElement element = null;
        try {
            element = new WebDriverWait(mDriver, TIMEOUT).until(new ExpectedCondition<WebElement>() {
                @Override
                public WebElement apply(WebDriver d) {
                    return d.findElement(by);
                }
            });
        } catch (Exception e) {
            Log.info("等待" + TIMEOUT + "s,对象" + by.toString() + "未定位成功");
        }
        return element;
    }

    private By getBy(String page, String object) {
        By by = null;
        String type = xp.getElementText("/对象/" + page + "/" + object + "/type");
        String value = xp.getElementText("/对象/" + page + "/" + object + "/value");

        if (xp.isExist("/对象/" + page + "/" + object)) {
            switch (type.toLowerCase().trim()) {
                case "id":
                    by = By.id(value);
                    break;
                case "classname":
                    by = By.className(value);
                    break;
                case "linktext":
                    by = By.linkText(value);
                    break;
                case "name":
                    by = By.name(value);
                    break;
                case "partiallinktext":
                    by = By.partialLinkText(value);
                    break;
                case "tagname":
                    by = By.tagName(value);
                    break;

                case "xpath":
                    by = By.xpath(value);
                    break;

                default:
                    Log.info("定位方式类型不存在");
                    break;
            }

        } else {
            Log.info("对象" + page + "-" + object + "在objectxml中不存在");
        }

        return by;

    }


}
